import csv
import urllib2
import libxml2
from os import path


ORIGINATING_SOURCE_TYPE = [('authoritative',
                            'Authoritative: the source holds the authoritative'
                            ' version of the metadata about the registry'
                            ' object')]

COLLECTION_TYPES = [('repository',
                     'Repository: collection of physical or digital objects'
                     ' compiled for information and documentation purposes'
                     ' and/or for storage and safekeeping'),
                    ('catalogueOrIndex',
                     'Catalogue Or Index: collection of resource descriptions describing the'
                     ' content of one or more repositories or collective'
                     ' works'),
                    ('registry',
                     'Registry: collection of registry objects compiled to support the'
                     ' business of a given community'),
                    ('collection',
                     'Collection: compiled content created as separate and independent'
                     ' works and assembled into a collective whole for'
                     ' distribution and use'),
                    ('dataset',
                     'Dataset: collection of physical or digital objects generated by'
                     ' research activities')]

COLLECTION_TYPES_KEYS = [k[0] for k in COLLECTION_TYPES]

DESCRIPTION_TYPE = [('full', 'Full Account: full account'),
                    ('rights',
                     'Rights: (collections only) information about rights held in and'
                     ' over the collection'),
                    ('brief', 'Brief: short account for selection purposes'),
                    ('accessRights',
                     'Access Rights: (collections and services) information about access'
                     ' rights to the collection or service.'),
                    ('note',
                     'Note: a brief informational message, not object metadata, to'
                     ' notify the record consumer of some important aspect'
                     ' regarding the object or its metadata'),
                    ('logo', 'Logo: symbol used as an identifying mark')]
DESCRIPTION_TYPE_KEYS = [k[0] for k in DESCRIPTION_TYPE]

SPATIAL_TYPE = [('iso19139dcmiBox',
                 'ISO19139 DCMI Box: DCMI Box notation derived from bounding box metadata'
                 ' conformant with the iso19139 schema'),
                ('kml', 'KML: Keyhole Markup Language developed for use with Google'
                 ' Earth'),
                ('gpx', 'GPS: the GPS Exchange Format'),
                ('kmlPolyCoords',
                 'KML Poly co-ordinates: A set of KML long/lat co-ordinates defining a polygon as'
                 ' described by the KML coordinates element'),
                ('gml', 'GML: OpenGIS Geography Markup Language (GML) Encoding'
                 ' Standard'),
                ('iso31661',
                 'ISO 3166-1: ISO 3166-1 Codes for the representation of names of'
                 ' countries and their subdivisions - Part 1: Country codes'),
                ('text', 'Text: free-text representation of spatial location'),
                ('iso31662',
                 'ISO31662: Codes for the representation of names of countries and their'
                 ' subdivisions - Part 2: Country subdivision codes'),
                ('gmlKmlPolyCoords',
                 'GML KML Poly co-ordinates: A set of KML long/lat co-ordinates derived from GML defining'
                 ' a polygon as described by the KML coordinates element but'
                 ' without the altitude component'),
                ('dcmiPoint',
                 'DCMI Point: spatial location information specified in DCMI Point'
                 ' notation')]
SPATIAL_TYPE_KEYS = [k[0] for k in SPATIAL_TYPE]

LOCATION_TYPE = [('coverage', 'Coverage: spatial and temporal coverage metadata')]
LOCATION_TYPE_KEYS = [k[0] for k in LOCATION_TYPE]

PHYSICAL_ADDRESS_TYPE = [('streetAddress',
                          'Street Address: address where the registry object is physically'
                          ' located'),
                         ('postalAddress',
                          'Postal Address: address where mail for the registry object should'
                          ' be directed')]
PHYSICAL_ADDRESS_TYPE_KEYS = [k[0] for k in PHYSICAL_ADDRESS_TYPE]

COLLECTION_RELATIONSHIP_TYPE = [('hasAssociationWith',
                                 'has Association With: has an undefined'
                                 ' relationship with the related collection'),
                                ('hasPart', 'has Part: contains the related'
                                 ' collection'),
                                ('isManagedBy', 'is Managed By: is maintained'
                                 ' and made accessible by the related party'),
                                ('isLocatedIn', 'is Located In: is held in'
                                 ' the related repository'),
                                ('hasCollector', 'has Collector: has been'
                                 ' aggregated by the related party'),
                                ('isDescribedBy', 'is Described By: is'
                                 ' catalogued or indexed by'
                                 ' the related collection'),
                                ('isOwnedBy', 'is Owned By: legally belongs'
                                 ' to the related party'),
                                ('isLocationFor', 'is Location For: is the'
                                 ' repository where the'
                                 ' related collection is held'),
                                ('isOutputOf', 'is Output Of: is a product'
                                 ' of the related activity'),
                                ('describes',
                                 'Describes: is a catalogue for, or index'
                                 ' of, of items in'
                                 ' the related collection'),
                                ('isPartOf', 'is Part Of: is contained within'
                                 ' the related collection'),
                                ('supports',
                                 'Supports: can be contributed to, accessed'
                                 ' or used through the related service')]
COLLECTION_RELATIONSHIP_TYPE_KEYS = [k[0] for k in COLLECTION_RELATIONSHIP_TYPE]

ADDRESS_PART_TYPE = [('text',
                      'Text: a single address part that contains the whole'
                      ' address in unstructured form'),
                     ('addressLine',
                      'Address Line: an address part that is a separate line'
                      ' of a structured address')]
ADDRESS_PART_TYPE_KEYS = [k[0] for k in ADDRESS_PART_TYPE]

NAME_TYPE = [('alternative',
              'Alternative: any other form of name used now or in the past as'
              ' a substitute or alternative for the official name'),
             ('abbreviated',
              'Abbreviated: shortened form of, or acronym for, the official'
              ' name'),
             ('primary',
              'Primary: official name of the registry object')]
NAME_TYPE_KEYS = [k[0] for k in NAME_TYPE]

NAME_PART_TYPE = [('title',
                   'Title: word or phrase indicative of rank, office,'
                   ' nobility, honour, etc., or a term of address'
                   ' associated with a person'),
                  ('given',
                   'Given: forenames or given or Christian names or initials'),
                  ('family',
                   'Family: last name or surname'),
                  ('suffix',
                   'Suffix: honours, awards, qualifications and other'
                   ' identifiers conferred')]
NAME_PART_TYPE_KEYS = [k[0] for k in NAME_PART_TYPE]


IDENTIFIER_TYPE = [('isil', 'ISIL: International Standard Identifier for Libraries'),
                   ('purl', 'PURL: Persistent Uniform Resource Locator'),
                   ('arc', 'ARC: Australian Research Council identifier'),
                   ('handle', 'HANDLE: HANDLE System Identifier'),
                   ('infouri', "info URI: 'info' URI scheme"),
                   ('ark', 'ARK: ARK Persistent Identifier Scheme'),
                   ('local', 'Local Identifier: identifer unique within a'
                    ' local context'),
                   ('uri', 'URI: Uniform Resource Identifier'),
                   ('abn', 'ABN: Australian Business Number'),
                   ('doi', 'DOI: Digital Object Identifier')]
IDENTIFIER_TYPE_KEYS = [k[0] for k in IDENTIFIER_TYPE]

ELECTRONIC_ADDRESS_TYPE = [('fax',
                            'FAX: string used to receive scanned images of'
                            ' documents via telephone lines'),
                           ('url', 'URL: Uniform Resource Locator'),
                           ('other', 'Other: other electronic address'),
                           ('wsdl', 'WSDL: (service only) Web Service'
                            ' Definition Language'),
                           ('voice',
                            'Voice: string used to recieve calls by means of a'
                            ' telephone line or computer network'),
                           ('email',
                            'Email: string used to receive messages by means'
                            ' of a computer network')]
ELECTRONIC_ADDRESS_TYPE_KEYS = [k[0] for k in ELECTRONIC_ADDRESS_TYPE]

ELECTRONIC_ADDRESS_ARG = [('String',
                           'string: (service only) Indicates the value of'
                           ' an argument is a plain text string'),
                          ('Object',
                           'object: indicates the value of an argument is'
                           ' an object, most likely in serialized form')]
ELECTRONIC_ADDRESS_ARG_KEYS = [k[0] for k in ELECTRONIC_ADDRESS_ARG]


def for2008(filename=path.join(path.dirname(__file__), "for2008.csv")):
    with open(filename) as for_codes:
        reader = csv.reader(for_codes)
        for code in reader:
            yield {"value": code[0],
                   "label": unicode(code[1], 'utf-8'),
                   "type": "anzsrc-for",
                   }


def for2008list(filename=path.join(path.dirname(__file__), "for2008.csv")):
    with open(filename) as for_codes:
        reader = csv.reader(for_codes)
        for code in reader:
            yield (code[0], unicode(code[1], 'utf-8'),)


class CcRest:
    """Wrapper class to decompose REST XML responses into Python objects."""

    def __init__(self, root, lang='en'):
        self.root = root
        self.lang = lang

        self.__lc_doc = None

    def license_classes(self):
        """Returns a dictionary whose keys are license IDs, with the
        license label as the value."""

        lc_url = '%s/%s' % (self.root, '?locale=%s' % self.lang)

        # retrieve the licenses document and store it
        self.__lc_doc = urllib2.urlopen(lc_url).read()

        # parse the document and return a dictionary
        lc = {}
        d = libxml2.parseMemory(self.__lc_doc, len(self.__lc_doc))
        c = d.xpathNewContext()

        licenses = c.xpathEval('//licenses/license')

        for l in licenses:
            lc[l.xpathEval('@id')[0].content] = l.content

        return lc

    def fields(self, license):
        """Retrieves details for a particular license."""

        l_url = '%s/license/%s?locale=%s' % (self.root, license, self.lang)

        # retrieve the license source document
        self.__l_doc = urllib2.urlopen(l_url).read()

        d = libxml2.parseMemory(self.__l_doc, len(self.__l_doc))
        c = d.xpathNewContext()

        self._cur_license = {}
        keys = []

        fields = c.xpathEval('//field')

        for field in fields:
            f_id = field.xpathEval('@id')[0].content
            keys.append(f_id)

            self._cur_license[f_id] = {}

            self._cur_license[f_id]['label'] = \
                            field.xpathEval('label')[0].content
            self._cur_license[f_id]['description'] = \
                            field.xpathEval('description')[0].content
            self._cur_license[f_id]['type'] = \
                            field.xpathEval('type')[0].content
            self._cur_license[f_id]['enum'] = {}

            # extract the enumerations
            enums = field.xpathEval('enum')
            for e in enums:
                e_id = e.xpathEval('@id')[0].content
                self._cur_license[f_id]['enum'][e_id] = \
                     e.xpathEval('label')[0].content

        self._cur_license['__keys__'] = keys
        return self._cur_license

    def issue(self, license, answers, work_info=None):
        l_url = '%s/license/%s/issue' % (self.root, license)

        # construct the answers.xml document from the answers dictionary
        answer_xml = """
        <answers>
          <license-%s>""" % license

        for key in answers:
            answer_xml = """%s
            <%s>%s</%s>""" % (answer_xml, key, answers[key], key)

        answer_xml = """%s
          </license-%s>
          %%s
        </answers>
        """ % (answer_xml, license)

        if work_info:
            answer_xml %= (
                      '<work-info>' + \
                        '\n'.join(['<%s>%s</%s>' % (k,v,k)
                                   for k,v in work_info.items()]) + \
                      '</work-info>')
        else:
            answer_xml %= ''

        # retrieve the license source document
        try:
            self.__a_doc = urllib2.urlopen(l_url,
                                     data='answers=%s' % answer_xml).read()
        except urllib2.HTTPError:
            self.__a_doc = ''

        return self.__a_doc


def cc_getLicenseClasses():
    REST_ROOT = 'http://api.creativecommons.org/rest/dev'
    j = CcRest(REST_ROOT)
    classes = j.license_classes()
    del classes['mark']
    del classes['publicdomain']
    del classes['recombo']
    classes['custom'] = "Define your own rights"
    yield ("", "-Select-")
    for lclass in  classes.items():
        yield lclass


def split_uppercase(string):
    x = ''
    for i in string:
        if i.isupper():
            x += ' %s' % i
        else:
            x += i
    return x.strip()


def cc_getLicense(license):
    REST_ROOT = 'http://api.creativecommons.org/rest/dev'
    LOCALE = "en-au"
    j = CcRest(REST_ROOT)
    fields = j.fields(license)
    for k, v in fields.items():
        if not isinstance(v, dict):
            continue
        for option in v.get("enum", {}):
            v['enum'][option] = split_uppercase(v['enum'][option])
    return fields


def cc_renderLicense(license_data):
    REST_ROOT = 'http://api.creativecommons.org/rest/dev'
    j = CcRest(REST_ROOT)
    lclass = license_data['license_class']
    del license_data['license_class']
    license_text = j.issue(lclass, license_data)
    d = libxml2.parseMemory(license_text, len(license_text))
    c = d.xpathNewContext()

    license_text = {}
    license_text['license-name'] = c.xpathEval('//license-name')[0].content
    return license_text
